package utilLayer;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import dbLayer.*;
import modelLayer.Block;
import modelLayer.Schedule;
import modelLayer.TeachingBlock;

public class Validator {
	
	private DBBlockIF dbBlock;
	
	/**
	 * This class is a utility layer class of the MSAS system. It functions as a conflict check,
	 * checking to see if an association between Block and Teachingblock is legal. 
	 * 
	 * @author Danny M�lgaard, Anna Kelemen, Jakob Korsgaard
	 * 		   
	 * @version 1.4.1
	 * 					1.3.1: 		Added more extensive documentation. Verified that
	 * 								information contained in the Design Class Diagram,
	 * 								is in accordance with the information contained in this
	 * 								class.
	 * 					1.4.1:		Made checkSubjectConflict() unavailable, implemented
	 * 								checkTeacherConflict in its stead.
	 */
	public Validator(){
		
		this.dbBlock = new DBBlock();
		
	}

	/**
	 * This method performs a conflict check on a Block and TeachingBlock respectively.
	 * This check is necessary, since it's not allowed for a subject to be taught at the same
	 * time in two places, just as it's not allowed for a classroom to be booked by two parties.
	 * 
	 * Initially, this instantiates a list of blocks, in which all blocks have a teachingblock associated
	 * with them. If this list is not empty, it will first check for a conflict with teachers, and then classroom.
	 * If the list is empty, then no conflict can arise, and the method therefore returns false.
	 * If any conflict arises during these checks, the method will return true, indicating that the teachingblock
	 * cannot be placed in this block.
	 * 
	 * @param 	blockNumber		int		the number of the block in question
	 * @param 	tb				int		the teachingblock to be associated with the block
	 * @return	conflict		boolean	if a conflict arose or not
	 */
	public boolean checkConflict(int blockNumber, TeachingBlock tb) {
		
		boolean conflict = false;		
		try {
			List<Block> blocks = this.dbBlock.findFilledBlocksByNumber(blockNumber, true);
			if (!blocks.isEmpty()) {
				if (checkTeacherConflict(blocks, tb)) {
					conflict = true;
				}
				else if (checkClassroomConflict(blocks, tb)) {
					conflict = true;
				}
			}
		}
		catch(Exception e) {
			System.out.println("DEBUG MESSAGE [VALIDATOR]: checkConflict(): " + e);
		}	

		return conflict;

	}
	
	/**
	 * This method returns a list to the caller, containing all available blocks, for which an
	 * associated teachingblock would cause no conflict.
	 * 
	 * Initially, the method instantiates a list of available blocks, by getting all the blocks,
	 * in a given schedule, and not including the block with the given blocknumber (the conflicting block).
	 * It then goes through the list using an iterator, and runs a conflict check on each block. If there's a
	 * conflict, it removes the block from the list. It then acquires a filtered block list, in which all
	 * blocks in the schedule that has a teachingblock associated with it, is removed in order to avoid 
	 * overwritting a block unintentionally.	 * 
	 * 
	 * @param	sch			Schedule			an instance of Schedule
	 * @param	blockNumber	int					the number of the specific block in the schedule
	 * @param 	tb			TeachingBlock		an instance of TeachingBlock
	 * @return				List<Integer>		a list of blocknumbers available for association with
	 * 											a teachingblock
	 * @throws 				Exception 
	 */
	public List<Integer> showSuggestions(Schedule sch, int blockNumber, TeachingBlock tb) throws Exception {
		
		List<Block> availableBlocks = this.dbBlock.getAllNonConflictingBySchedule(sch.getId(), true, blockNumber);
		
		try {
			Iterator<Block> it = availableBlocks.iterator();
			while (it.hasNext()){ 
				Block b = it.next();
				if (checkConflict(b.getBlockNumber(), tb)) {
					it.remove();
				}
			}
		}
		catch (Exception e) {
			System.out.println("DEBUG MESSAGE [VALIDATOR]: showSuggestions(): " + e);
		}
		
		//List<Block> filteredAvailableBlocks = filterAvailableBlocks(availableBlocks);
		
		//return getFreePlaces(filteredAvailableBlocks);
		return getFreePlaces(availableBlocks);

	}

//	/**
//	 * This method performs a conflictcheck on subject. It checks all blocks with a given
//	 * blocknumber, and should a conflict arise, notify the caller.
//	 * 
//	 * It initially runs through all the blocks in the given collection, and checks if the
//	 * subject is the same in any of the blocks. If it's the same between any two blocks,
//	 * it results in a conflict.
//	 * 
//	 * @param 	blocks		List<Block>		a given list of blocks
//	 * @param 	tb			TeachingBlock	a given teachingblock to be associated with the block
//	 * @return	conflict	boolean			determines if a conflict arose or not
//	 */
//	private boolean checkSubjectConflict(List<Block> blocks, TeachingBlock tb) {
//		
//		boolean conflict = false;
//		
//		try {
//			boolean condition = false;
//			int i = 0;
//			while (!condition && i < blocks.size()){
//				if (blocks.get(i).getTeachingBlock().getSubject().equals(tb.getSubject())) {
//					if (checkTeacherConflict(blocks.get(i).getTeachingBlock(), tb)) {
//						condition = true;
//						conflict = true;
//					}
//				}
//				else {
//					++i;
//				}
//			}
//		}
//		catch (Exception e) {
//			System.out.println("DEBUG MESSAGE [VALIDATOR]: checkSubjectConflict(): " + e);
//		}
//		
//		return conflict;
//		
//	}

	/**
	 * This method performs a conflictcheck on teacher. It checks all blocks with a given
	 * blocknumber, and should a conflict arise, notify the caller.
	 * 
	 * It initially runs through all the blocks in the given collection, and checks if the
	 * teacher is the same in any of the blocks. If it's the same between any two blocks,
	 * it results in a conflict.
	 * 
	 * @param 	blocks		List<Block>		a given list of blocks
	 * @param 	tb			TeachingBlock	a given teachingblock to be associated with the block
	 * @return	conflict	boolean			determines if a conflict arose or not
	 */
	private boolean checkTeacherConflict(List<Block> blocks, TeachingBlock tb) {

		boolean conflict = false;
		
		try {
			boolean condition = false;
			int i = 0;
			while (!condition && i < blocks.size()) {
				if (blocks.get(i).getTeachingBlock().getTeacher().equals(tb.getTeacher())) {
					condition = true;
					conflict = true;
				}
				else {
					++i;
				}
			}
		}
		catch (Exception e) {
			System.out.println("DEBUG MESSAGE [VALIDATOR]: checkTeacherConflict(): " + e);
		}
		
		return conflict;	

	}

	/**
	 * This method performs a conflictcheck on classroom. It checks all blocks with a given
	 * blocknumber, and should a conflict arise, notify the caller.
	 * 
	 * It initially runs through all the blocks in the given collection, and checks if the
	 * classroom is the same in any of the blocks. If it's the same between any two blocks,
	 * it results in a conflict.
	 * 
	 * @param 	blocks		List<Block>		a given list of blocks
	 * @param 	tb			TeachingBlock	a given teachingblock to be associated with the block
	 * @return	conflict	boolean			determines if a conflict arose or not
	 */
	private boolean checkClassroomConflict(List<Block> blocks, TeachingBlock tb) {
		
		boolean conflict = false;
		
		try {
			boolean condition = false;
			int i = 0;
			while (!condition && i < blocks.size()){
				if (blocks.get(i).getTeachingBlock().getClassRoom().equals(tb.getClassRoom())){
					condition = true;
					conflict = true;
				}
				else {
					++i;
				}
			}
		}
		catch (Exception e){
			System.out.println("DEBUG MESSAGE [VALIDATOR]: checkClassRoomConflict(): " + e);
		}
		
		return conflict;
		
	}
		
//	/**
//	 * This methods filters the list provided from showSuggestions(...), it removes all blocks
//	 * in which there's a teachingblock associated with.
//	 * 
//	 * @param availableBlocks
//	 * @return
//	 */
//	private List<Block> filterAvailableBlocks(List<Block> availableBlocks) {
//
//		List<Block> list = availableBlocks;
//		try {
//			Iterator<Block> it = list.iterator();
//			while (it.hasNext()){
//				Block b = it.next();
//				if (b.getTeachingBlock() != null){
//					it.remove();
//				}
//			}
//		}
//		catch (Exception e) {
//			System.out.println("DEBUG MESSAGE [VALIDATOR]: filterAvailableBlocks(): " + e);
//		}
//		
//		return list;
//		
//	}

	/**
	 * This method returns a list based on the given list from showSuggestions(...). It creates
	 * a new list containing integer values, more specifically the respective blocks blocknumbers.
	 * 
	 * @param 	available	List<Block>		a filtered list of blocks
	 * @return	freePlaces	List<Integer>	a list containing block numbers
	 */
	private List<Integer> getFreePlaces(List<Block> available) {
		
		List<Integer> freePlaces = new ArrayList<Integer>();
		try {
			for (Block b : available) {
				freePlaces.add(b.getBlockNumber());
			}	
		}
		catch (Exception e) {
			System.out.println("DEBUG MESSAGE [VALIDATOR]: getFreePlaces(): " + e);
		}
		
		return freePlaces;
	
	}
	
}
